/*
** SMSE2K Simple Timer System
**
** TODO: complete rewrite of this to use a single timer system instead of individual timers.
*/

#include "smse2kincludes.h"

/*
CTimer::CTimer() {
		timeLeft = 0.0;
		initialTime = 0.0;
		timerEnabled = 0;
		callback = NULL;
		isInVblankMode = 0;
		destCpuLine = 0;
		destCpu = NULL;
}
*/

CTimer::CTimer(CHardware* hardware) {
		Msg("Creating a new timer\n");
		timeLeft = 0.0;
		initialTime = 0.0;
		timerEnabled = 0;
		callback = NULL;
		isInVblankMode = 0;
		destCpuLine = 0;
		destCpu = NULL;
		this->hardware = hardware;

		// add timer to hardware on creation
		hardware->AddTimer(this);
}

void CTimer::Run(double time) {
		if (!timerEnabled) 		
			return; // don't run if the timer isn't enabled.
		
		//Msg("Timer %p: %f run, %f left\n",time,timeLeft);
		timeLeft -= time;

		if (!time) {
			Msg("Timer cannot run (specified %f seconds)\n",time);
		}

		// Check for timer expiry
		if (timeLeft <= 0.00) {

			// inform scheduler that a timer expired
			//Msg("TIMER FIRED\n");
			hardware->TimerFired();

			if (isInVblankMode && destCpu) {
					destCpu->Interrupt(destCpuLine, HOLD_LINE); // fire the interrupt
					timeLeft = initialTime;						// reset the timer

		//			Msg("IRQ Timer Fired\n");
					return;
			}
			
			// Stop the timer if it isn't being used for vsync. We need to wait for something else to re-enable it
			timerEnabled = 0;

			// We almost always have a callback for a timer, but the check is here nonetheless. Run it
			if (callback) callback->Timer_Expired(this);
		}

}

void CTimer::SetupAsVBlank(double interval, ICpu* dest, int line) {
	this->initialTime = interval;
	this->destCpu     = dest;
	this->destCpuLine = line;
	isInVblankMode    = 1;
	this->timerEnabled = 1;
}

void CTimer::SetStatus (int status) {
	timerEnabled = status;
}

void CTimer::SetTimerCallback(ITimerCallback* cb) {
	callback = cb;
}

void CTimer::Stop() {
	timeLeft = 0.0;
	timerEnabled = 0;
}

void CTimer::SetLength(double interval) {
	this->initialTime = interval;
}

void CTimer::Reset() {
	timeLeft = initialTime;
	timerEnabled = 1;
}